package base.core.util;

import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.Locale;

import lombok.extern.slf4j.Slf4j;

/**
 * 项目--项目跟踪日志
 *
 * @author 陈彭伟
 * @since 2021-08-21 19:03:50
 */
@Slf4j
public class Dates {
    private Dates() {
    }

    //针对"Oct 1, 1959 12:00:00 AM"的格式,必须设置"Locale.ENGLISH",否则无法解析
    public static final DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
            .appendOptional(DateTimeFormatter.ofPattern("MMM d, yyyy K:m:s a"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy.MM.dd"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy-M-dd"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy/MM/dd"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyy/M/dd"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSS"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyyMMddHHmm"))
            .appendOptional(DateTimeFormatter.ofPattern("yyyyMMdd"))
            .appendOptional(DateTimeFormatter.ofPattern("HH:mm:ss"))
            .appendOptional(DateTimeFormatter.ofPattern("HHmmss"))
            .toFormatter(Locale.ENGLISH);

    public static LocalDateTime asLocalDateTime(String string) {
        if (StringUtils.isBlank(string)) {
            return null;
        }
        try {
            return LocalDateTime.parse(string, dateTimeFormatter);
        } catch (Exception e) {
            log.error("{} asLocalDateTime error ", string, e);
        }
        return null;
    }

    public static LocalDateTime asLocalDateTime(String string, String format) {
        if (StringUtils.isBlank(string) || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            return LocalDateTime.parse(string, DateTimeFormatter.ofPattern(format));
        } catch (Exception e) {
            log.error("{} asLocalDateTime error ", string, e);
        }
        return null;
    }

    public static LocalDateTime asLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        try {
            return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        } catch (Exception e) {
            log.error("Date asLocalDateTime error ", e);
        }
        return null;
    }

    public static LocalDate asLocalDate(String string) {
        if (StringUtils.isBlank(string)) {
            return null;
        }
        try {
            return LocalDate.parse(string, dateTimeFormatter);
        } catch (Exception e) {
            log.error("{} asLocalDate error ", string, e);
        }
        return null;
    }

    public static LocalDate asLocalDate(String string, String format) {
        if (StringUtils.isBlank(string) || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            return LocalDate.parse(string, DateTimeFormatter.ofPattern(format));
        } catch (Exception e) {
            log.error("{} asLocalDate error ", string, e);
        }
        return null;
    }

    public static LocalDate asLocalDate(Date date) {
        if (date == null) {
            return null;
        }
        try {
            return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        } catch (Exception e) {
            log.error("Date asLocalDate error ", e);
        }
        return null;
    }

    public static LocalTime asLocalTime(String string) {
        if (StringUtils.isBlank(string)) {
            return null;
        }
        try {
            return LocalTime.parse(string, dateTimeFormatter);
        } catch (Exception e) {
            log.error("{} asLocalTime error ", string, e);
        }
        return null;
    }

    public static LocalTime asLocalTime(String string, String format) {
        if (StringUtils.isBlank(string) || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            return LocalTime.parse(string, DateTimeFormatter.ofPattern(format));
        } catch (Exception e) {
            log.error("{} asLocalTime error ", string, e);
        }
        return null;
    }

    public static LocalTime asLocalTime(Date date) {
        if (date == null) {
            return null;
        }
        try {
            return date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
        } catch (Exception e) {
            log.error("Date asLocalTime error ", e);
        }
        return null;
    }

    public static Date asDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        try {
            return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        } catch (Exception e) {
            log.error("LocalDateTime asLocalTime error ", e);
        }
        return null;
    }

    public static Date asDate(LocalDate localDate) {
        if (localDate == null) return null;
        try {
            ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
            return Date.from(zonedDateTime.toInstant());
        } catch (Exception e) {
            log.error("LocalDate asLocalTime error ", e);
        }
        return null;
    }

    public static Date asDate(String date, String format) {
        if (StringUtils.isBlank(date) || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.parse(date);
        } catch (Exception e) {
            log.error("{} asDate error ", date, e);
        }
        return null;
    }

    public static Date asDate(String date) {
        if (date == null) {
            return null;
        }
        LocalDateTime localDateTime = asLocalDateTime(date);
        if (localDateTime != null) {
            return asDate(localDateTime);
        }
        LocalDate localDate = asLocalDate(date);
        if (localDate != null) {
            return asDate(localDate);
        }
        return null;
    }

    public static String asString(LocalDateTime localDateTime, String format) {
        if (localDateTime == null || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            return localDateTime.format(DateTimeFormatter.ofPattern(format));
        } catch (Exception e) {
            log.error("LocalDateTime asString error ", e);
        }
        return null;
    }

    public static String asString(LocalDate localDate, String format) {
        if (localDate == null || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            return localDate.format(DateTimeFormatter.ofPattern(format));
        } catch (Exception e) {
            log.error("LocalDate asString error ", e);
        }
        return null;
    }

    public static String asString(LocalTime localTime, String format) {
        if (localTime == null || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            return localTime.format(DateTimeFormatter.ofPattern(format));
        } catch (Exception e) {
            log.error("LocalTime asString error ", e);
        }
        return null;
    }

    public static String asString(Date date, String format) {
        if (date == null || StringUtils.isBlank(format)) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.format(date);
        } catch (Exception e) {
            log.error("Date asString error ", e);
        }
        return null;
    }

    /**
     * 获取一天的开始时间
     */
    public static LocalDateTime asStartTime(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }
        return LocalDateTime.of(localDate, LocalTime.MIN);
    }
    public static LocalDateTime asStartTime(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN);
    }

    /**
     * 获取一天的结束
     */
    public static LocalDateTime asEndTime(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }
        return LocalDateTime.of(localDate, LocalTime.MAX);
    }
    public static LocalDateTime asEndTime(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
    }

    /**
     * 获取后一天
     */
    public static <T extends Temporal> T asNextDay(T date) {
        if (date == null) {
            return null;
        }
        return (T)date.plus(1, ChronoUnit.DAYS);
    }

    /**
     * 获取前一天
     */
    public static <T extends Temporal> T asPreDay(T date) {
        if (date == null) {
            return null;
        }
        return (T)date.minus(1, ChronoUnit.DAYS);
    }
}

